package com.example.log.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class LogRequestWrapper extends HttpServletRequestWrapper {
	private HeadLogInputStream logInputStream = null;
	private StringBuilder sb = null;
	public LogRequestWrapper(HttpServletRequest request) throws IOException {
		super(request);
		sb = new StringBuilder("\n=====request info:=====");
		sb.append("\nrequest Url:");
		sb.append(request.getRequestURL());
		sb.append("\nrequest method:");
		sb.append(request.getMethod());
		sb.append("\nrequest address:");
		sb.append(request.getRemoteAddr());
		sb.append(":");
		sb.append(request.getRemotePort());
		sb.append("\n-----header info:-----");
		Enumeration<String> headerNameEnu = request.getHeaderNames();
		while(headerNameEnu.hasMoreElements()){
			String headerName = headerNameEnu.nextElement();
			Enumeration<String> headerValues = request.getHeaders(headerName);
			while(headerValues.hasMoreElements()){
				String headerValue = headerValues.nextElement();
				sb.append("\n"+headerName+":"+headerValue);
			}
		}
		//至少在tomcat的实现中，解析parameter时，并不占用usingStream标志
		//但反过来，先取inputStream，再解析parameter，会直接跳过解析过程
		Map<String, String[]> paramMap = request.getParameterMap();
		if(!paramMap.isEmpty()){
			sb.append("\n-----request parameter data:-----");
			for(Entry<String, String[]> entry:paramMap.entrySet()){
				for(String value:entry.getValue()){
					sb.append("\n").append(entry.getKey()).append(":").append(value);
				}
			}
		}
		String encoding = request.getCharacterEncoding();
		if(encoding==null){
			encoding = "ISO8859-1";
		}
		logInputStream = new HeadLogInputStream(request.getInputStream(), 1024*16);//仅处理前16k字节的信息
		String  strRawData = StringUtil.getLogFormatedBytes(logInputStream.getBuffer(), 0, logInputStream.getBufferSize(),  encoding);
		if(strRawData.length()>0){
			sb.append("\n-----request raw data:-----\n");
			sb.append(strRawData);
		}
		logInputStream.resetBufferOffset();
	}
	
	public String getLogString(){
		return sb.toString();
	}
	
	@Override
	public ServletInputStream getInputStream() throws IOException { 
		return logInputStream;
	}
	
	public static class HeadLogInputStream extends ServletInputStream{
		private InputStream is = null;
		private byte[] buffer;
		private int bufferSize = 0;
		private int bufferOffset = 0;
		public HeadLogInputStream(InputStream is, int logSize) throws IOException {
			this.is = is;
			buffer = new byte[logSize];
			int readSize = 0;
			while(buffer.length-bufferSize>0&&(readSize=is.read(buffer, bufferSize, buffer.length-bufferSize))!=-1) {
				bufferSize+=readSize;
			} 
		}

		@Override
		public int read() throws IOException {
			if(bufferOffset<bufferSize){
				return buffer[bufferOffset++]&0xff;
			}else{
				if(bufferOffset<buffer.length){//bufferOffset小于buffer.length，说明buffer未读满就已到结束位置
					return -1;
				}else{
					return is.read();
				}
			}
		}
		
		public byte[] getBuffer() {
			return buffer;
		}
		
		public int getBufferSize() {
			return bufferSize;
		}
		
		public void resetBufferOffset(){
			bufferOffset = 0;
		}

		@Override
		public boolean isFinished() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean isReady() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public void setReadListener(ReadListener listener) {
			// TODO Auto-generated method stub
			
		}
	}
}
